/*
 * COPYRIGHT. ShenZhen JiMi Technology Co., Ltd. 2017.
 * ALL RIGHTS RESERVED.
 *
 * No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
 * on any form or by any means, electronic, mechanical, photocopying, recording, 
 * or otherwise, without the prior written permission of ShenZhen JiMi Network Technology Co., Ltd.
 *
 * Amendment History:
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2017年7月25日    li.shangzhi         Create the class
 * http://www.jimilab.com/
 */

package com.jimi.web.api.impl;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.jimi.dto.base.ApiResult;
import com.jimi.framework.annotation.log.LoggerProfile;
import com.jimi.framework.base.BaseApi;
import com.jimi.framework.bean.BeanUtil;
import com.jimi.web.api.IInstructionApiService;
import com.jimi.web.dto.input.SendInstructionInputDto;
import com.jimi.web.dto.output.CommandLogsOutputDto;
import com.jimi.web.dto.output.InstructionDetailsOutputDto;
import com.jimi.web.model.CommandLogsEntity;
import com.jimi.web.model.InstructionDetailsEntity;
import com.jimi.web.service.IInstructionService;
import com.jimi.web.util.CmdAPIContent;
import com.jimi.web.util.CmdUtil;
import com.jimi.web.util.DeviceUtil;
import com.jimi.web.util.Globals;

/**
 * @FileName InstructionApiServiceImpl.java
 * @Description:
 *
 * @Date 2017年7月25日 下午2:15:21
 * @author li.shangzhi
 * @version 1.0
 */
@Service
public class InstructionApiServiceImpl extends BaseApi implements IInstructionApiService {

	@Resource
	private IInstructionService instructionService;

	@Override
	@LoggerProfile(methodNote = "IInstructionApiService.getInstructionByMcType")
	public List<InstructionDetailsOutputDto> getInstructionByMcType(String mcType) {
		List<InstructionDetailsEntity> instList = instructionService.getInstructionByMcType(mcType);
		return (List<InstructionDetailsOutputDto>) BeanUtil.convertBeanList(instList, InstructionDetailsOutputDto.class);
	}

	@Override
	@LoggerProfile(methodNote = "IInstructionApiService.getCommandLogsByImei")
	public List<CommandLogsOutputDto> getCommandLogsByImei(String imei) {
		List<CommandLogsEntity> commandLogList = instructionService.getCommandLogsByImei(imei);
		for(CommandLogsEntity commandLogsEntity : commandLogList) {
			String content = commandLogsEntity.getContent();
			commandLogsEntity.setContent(CmdUtil.cmdDescMsg(content));
		}
		return (List<CommandLogsOutputDto>) BeanUtil.convertBeanList(commandLogList, CommandLogsOutputDto.class);
	}

	@Override
	@LoggerProfile(methodNote = "IInstructionApiService.sendInstruction")
	public ApiResult sendInstruction(SendInstructionInputDto inputDto) {
		final String userId = inputDto.getUserId();
		final String account = inputDto.getAccount();
		final String imei = inputDto.getImei();
		final String mcType = inputDto.getMcType();
		final String instId = inputDto.getInstId();
		final String instTemplate = inputDto.getInstTemplate();
		final String[] params = inputDto.getParams();
		final boolean isCover = inputDto.isCover();
		InstructionDetailsEntity instDetailsEntity = instructionService.getInstruction(mcType, instId, instTemplate);
		if (null == instDetailsEntity) {
			// 查不到要下发的指令，非法指令请求
			ApiResult result = new ApiResult();
			result.setResultCode(Globals.DeviceToCode.CommandsNot_support);
			result.setResultMsg("设备不支持该指令");
			logger.warn("设备{}不支持该指令，指令ID：{}，指令模板：{}。", imei, instId, instTemplate);
			return result;
		}
		boolean isOffLineFlag = Globals.InstructionCode.STATUS_YES.equals(instDetailsEntity.getIsOffLine());// 是否支持离线指令
		boolean isWaitRespondFlag = Globals.InstructionCode.STATUS_YES.equals(instDetailsEntity.getWaitRespond());// 是否等待设备响应标志
		// 指令参数组装
		String cmd = CmdUtil.maintanceCmd(instTemplate, params);
		// 指令发送
		String protocolStr = instDetailsEntity.getProtocolCode().toLowerCase();
		if (protocolStr.charAt(0) == '0' && protocolStr.charAt(1) == 'x') {
			protocolStr = protocolStr.substring(2);
		}
		Integer proNo = Integer.parseInt(protocolStr, 16);
		CmdAPIContent cmdresult = CmdUtil.sendNormalInstructionCmd(imei, cmd, proNo, isWaitRespondFlag);
		if (cmdresult.getCode() == 255) {// 指令执行成功
			CommandLogsEntity log = new CommandLogsEntity(account, imei, cmd, String.valueOf(instDetailsEntity.getId()), String.valueOf(cmdresult.getData()),
					Globals.CommandLog.PLATFORM_WEB, Globals.InstructionCode.EXCUTE_STATUS_SUCCESS, userId, userId,
					Globals.InstructionCode.STATUS_NO, instDetailsEntity.getOrderName(), null);
			instructionService.insertCommandLog(log);
		} else {
			if(!isWaitRespondFlag) {
				// 不用等待设备响应
				CommandLogsEntity log = new CommandLogsEntity(account, imei, cmd, String.valueOf(instDetailsEntity.getId()), "", Globals.CommandLog.PLATFORM_WEB,
						Globals.InstructionCode.EXCUTE_STATUS_SUCCESS, userId, userId, instDetailsEntity.getIsOffLine(), instDetailsEntity.getOrderName(), null);
				instructionService.insertCommandLog(log);
				ApiResult result = new ApiResult();
				result.setResultCode(0);
				result.setResultMsg("指令已异步下发。");
				logger.warn("设备{}指令已异步下发。指令ID：{}，指令模板：{}，指令参数：{}", imei, instId, instTemplate, params);
				return result;
			}
			// 支持离线指令(目前仅特殊机型支持离线指令)
			if (isOffLineFlag && cmdresult.getCode() == Globals.DeviceToCode.CommandsDevice_NONET) {
				// 设备处于离线状态，并且该指令支持离线指令
				// 查询数据库是否存在未执行的离线指令
				List<CommandLogsEntity> offlineLogs = instructionService.getNotExecutOfflineCommandLogs(imei);
				if (null != offlineLogs && offlineLogs.size() > 0) {
					// 存在未发送的指令，判断是否覆盖掉
					if(isCover) {
						// 覆盖现有离线指令
						instructionService.deleteOffLineCmdByImei(imei);
						
						CommandLogsEntity log = new CommandLogsEntity(account, imei, cmd, String.valueOf(instDetailsEntity.getId()), "", Globals.CommandLog.PLATFORM_WEB,
								Globals.InstructionCode.OFFLINE_STATUS_TOSEND, userId, userId, instDetailsEntity.getIsOffLine(), instDetailsEntity.getOrderName(), null);
						instructionService.insertCommandLog(log);
						
						DeviceUtil.saveOfflineInstToRedis(imei, cmd, log.getId(), proNo);
						
					} else {
						ApiResult result = new ApiResult();
						result.setResultCode(Globals.DeviceToCode.CommandsDevice_NONET);
						result.setResultMsg("已存在离线指令，并且不进行覆盖操作。");
						logger.warn("设备{}不在线，指令ID：{}，指令模板：{}，已存在离线指令，并且不进行覆盖操作。", imei, instId, instTemplate);
						return result;
					}
				} else {
					// 状态：离线待发送，存日志，存redis
					CommandLogsEntity log = new CommandLogsEntity(account, imei, cmd, String.valueOf(instDetailsEntity.getId()), "", Globals.CommandLog.PLATFORM_WEB,
							Globals.InstructionCode.OFFLINE_STATUS_TOSEND, userId, userId, instDetailsEntity.getIsOffLine(), instDetailsEntity.getOrderName(), null);
					instructionService.insertCommandLog(log);
					
					DeviceUtil.saveOfflineInstToRedis(imei, cmd, log.getId(), proNo);
				}
			} else {
				// 不支持离线指令，写日志，发送失败
				CommandLogsEntity log = new CommandLogsEntity(account, imei, cmd, String.valueOf(instDetailsEntity.getId()), CmdUtil.cmdDescCode(cmdresult
						.getCode()), Globals.CommandLog.PLATFORM_WEB, Globals.InstructionCode.EXCUTE_STATUS_FAILED, userId, userId,
						Globals.InstructionCode.STATUS_NO, instDetailsEntity.getOrderName(), null);
				instructionService.insertCommandLog(log);
				
				ApiResult result = new ApiResult();
				result.setResultCode(cmdresult.getCode());
				result.setResultMsg("设备不在线，不支持离线指令。");
				logger.warn("设备{}不在线，指令ID：{}，指令模板：{}，不支持离线指令，发送失败。", imei, instId, instTemplate);
				return result;
			}
		}
		ApiResult result = new ApiResult();
		result.setResultCode(0);
		result.setResultMsg("下发指令成功。");
		return result;
	}

}
